//注意1:mutex类对象不支持拷贝和移动,所以传参时需要传引用,因为传值传参是拷贝构造
//注意2:线程能够对原子类型互斥访问，所以不需要加锁保护原子类型变量
#include<iostream>
#include<thread>
#include<atomic>
#include<mutex>
using namespace std;

//创建两个线程分别打印1-n
#if 0
void func(int n,mutex& mtx)
{
  //方式1:for循环外部加锁  -> 提高效率,但是线程的执行变为了串行
  //方式2:for循环内部加锁  -> 频繁的加锁和解锁降低了效率
  mtx.lock();
  cout << "-----------------" << endl;
  for(int i = 0 ;i<n;i++)
  {
    cout << i << endl;
  }
  cout << "-----------------" << endl;
  mtx.unlock();

}
int main()
{
  mutex mtx;
  thread t1(&func,10,std::ref(mtx));
  thread t2(&func,10,std::ref(mtx));
  
  t1.join();
  t2.join();
  return 0;
}
#endif

//方法2:使用lambda作为线程函数,以引用方式捕获锁对象
//int main()
//{
//  mutex mtx;
//  int n = 5;
//  auto out = [&](int id){
//      mtx.lock();
//      cout << id << endl;
//      for(int i = 0;i<n;i++)
//      {
//        cout << i << endl;
//      }
//      mtx.unlock();
//  };
//
//  thread t1(out);
//  thread t2(out);
//  t1.join();
//  t2.join();
//  return 0;
//}

//两个线程对同一个变量自增n次 
//变量的++和--不是原子性操作,会有线程安全问题
//方法1:加锁
//int count = 0;
//void func(int n,mutex& mtx)
//{
//  mtx.lock();
//  for(int i = 0;i<n;i++)
//    count++;
//  mtx.unlock();
//}
//int main()
//{
//  mutex mtx;
//  thread t1(func,100000,std::ref(mtx));
//  thread t2(func,100000,std::ref(mtx));
//  t1.join();
//  t2.join();
//  cout << count << endl;
//  return 0;
//}
//方法2:使用原子类型
void func(atomic_int& n,int time)
{
  for(int i = 0;i<time;i++)
    n++;
}
int main()
{
  atomic_int n = {1};
  thread t1(func,std::ref(n),100000);
  thread t2(func,std::ref(n),100000);
  
  t1.join();
  t2.join();
  cout << n << endl;
  return 0;
}
